package com.net.io.nio.three.component.pathfile;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * @author zhangtengfei
 * @date 2022/1/28 14:08
 */
public class FileChannelTest {

    public static void main(String[] args) throws IOException {
        // 这里的"rw"是指支持读和写
        RandomAccessFile randomAccessFile = new RandomAccessFile("D:\\data.txt", "rw");
        FileChannel fileChannel = randomAccessFile.getChannel();

        // 读取文件内容：
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        int num = fileChannel.read(buffer);
        System.out.println("读取的数据量：" + num + "，内容为：\r\n" + new String(buffer.array()));

        buffer.clear();

        // 向文件内追加内容：祝源码班各位大帅比迎娶白富美！
        buffer.put("\r\n".getBytes());
        buffer.put("祝源码班各位大帅比迎娶白富美！".getBytes());

        buffer.flip();

        while (buffer.hasRemaining()) {
            // 将 Buffer 中的内容写入文件
            fileChannel.write(buffer);
        }
    }

    /**
     * 本地文件写数据
     * 写入数据到 fileChannel，从buffer中
     */
    public static void write() throws Exception {
        String str = "hello";
        //创建一个输出流->channel
        FileOutputStream fileOutputStream = new FileOutputStream("d:\\file01.txt");
        //通过 fileOutputStream 获取 对应的 FileChannel
        //这个 fileChannel 真实 类型是  FileChannelImpl
        FileChannel fileChannel = fileOutputStream.getChannel();
        //创建一个缓冲区 ByteBuffer
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        //将 str 放入 byteBuffer
        byteBuffer.put(str.getBytes());
        //对byteBuffer 进行flip
        byteBuffer.flip();
        //将byteBuffer 数据写入到 fileChannel
        fileChannel.write(byteBuffer);
        fileOutputStream.close();
    }


    /**
     * 本地文件读数据
     * 读取fileChannel的数据 到Buffer
     */
    public static void read() throws Exception {
        //创建文件的输入流
        File file = new File("d:\\file01.txt");
        FileInputStream fileInputStream = new FileInputStream(file);
        //通过fileInputStream 获取对应的FileChannel -> 实际类型  FileChannelImpl
        FileChannel fileChannel = fileInputStream.getChannel();
        //创建缓冲区
        ByteBuffer byteBuffer = ByteBuffer.allocate((int) file.length());
        //将 通道的数据读入到Buffer
        fileChannel.read(byteBuffer);
        //将byteBuffer 的 字节数据 转成String
        System.out.println(new String(byteBuffer.array()));
        fileInputStream.close();
    }


    /**
     * 拷贝文件transferFrom 方法
     */
    public static void transferFrom() throws Exception {
        //创建相关流
        FileInputStream fileInputStream = new FileInputStream("d:\\a.jpg");
        FileOutputStream fileOutputStream = new FileOutputStream("d:\\a2.jpg");

        //获取各个流对应的filechannel
        FileChannel sourceCh = fileInputStream.getChannel();
        FileChannel destCh = fileOutputStream.getChannel();

        //使用transferForm完成拷贝
        destCh.transferFrom(sourceCh, 0, sourceCh.size());
        //关闭相关通道和流
        sourceCh.close();
        destCh.close();
        fileInputStream.close();
        fileOutputStream.close();
    }

    public static void transferTo(String[] args) {
        try (FileChannel fromChannel = new FileInputStream("data.txt").getChannel();
             FileChannel toChannel = new FileOutputStream("to.txt").getChannel()) {
            // 效率高，底层会利用操作系统的零拷贝进行优化, 2g 数据
            long size = fromChannel.size();
            // left 变量代表还剩余多少字节
            for (long left = size; left > 0; ) {
                System.out.println("position:" + (size - left) + " left:" + left);
                left -= fromChannel.transferTo((size - left), left, toChannel);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
